package Eyjafjalla.patch;

import Eyjafjalla.card.AbstractEyjafjallaCard;
import Eyjafjalla.card.status.UnknownCloud_Eyjafjalla;
import Eyjafjalla.effect.FloatWordEffect;
import Eyjafjalla.effect.MelodyNoteFlashEffect;
import Eyjafjalla.helper.StringHelper;
import Eyjafjalla.modcore.EyjafjallaMod;
import Eyjafjalla.power.AdelePower;
import Eyjafjalla.power.AnswerInWindPower;
import Eyjafjalla.power.TranceDreamPower;
import Eyjafjalla.relic.GodRoll;
import Eyjafjalla.relic.UnknownMotherGoose;
import Eyjafjalla.relic.WitchAddax;
import Eyjafjalla.subscriber.MelodySubscriber;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.evacipated.cardcrawl.modthespire.lib.SpireInsertPatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePostfixPatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePrefixPatch;
import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.CardGroup;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.helpers.*;
import com.megacrit.cardcrawl.localization.UIStrings;
import com.megacrit.cardcrawl.monsters.AbstractMonster;
import com.megacrit.cardcrawl.monsters.MonsterGroup;
import com.megacrit.cardcrawl.powers.AbstractPower;
import com.megacrit.cardcrawl.relics.AbstractRelic;
import com.megacrit.cardcrawl.rooms.AbstractRoom;

import java.util.ArrayList;

public class MelodyPatch {

    public static final float MELODY_START_X;
    public static final float NOTE_DISTANCE_X;
    public static final float NOTE_DISTANCE_Y;
    public static final float BAR_HEIGHT;
    public static final float MELODY_BG_OFFSET_X;
    public static final float MELODY_BAR_OFFSET_Y;
    public static final float MELODY_DISTANCE_X;

    public static final float ALL_MELODY_START_X;
    public static final float ALL_MELODY_START_Y;

    public static final UIStrings melodyStrings;

    public static ArrayList<MelodySingle> singles = new ArrayList<>();
    public static MelodySingle lastSingle;
    public static MelodySingle currentSingle;

    public static void clear(){
        lastSingle = null;
        currentSingle = null;
        singles.clear();
    }

    public static MelodySingle getSingleByName(String name){
        MelodySingle single = null;
        for(MelodySingle s:singles){
            if(s.melodyName.equals(name))
                single = s;
        }
        return single;
    }

    public static void setCurrentMelody(MelodySingle single){
        if(single == null)
            return;
        currentSingle = single;
        currentSingle.started();
    }

    public static void removeCurrentMelody(){
        if(currentSingle!=null){
            currentSingle.finished();
            lastSingle = currentSingle;
            singles.remove(currentSingle);
            lastSingle.isAppearing = false;
            lastSingle.isFading = true;
            if(singles.size()>0){
                lastSingle.setTarget(lastSingle.currentTotalX,lastSingle.currentTotalY - NOTE_DISTANCE_Y,false);
            }
            currentSingle = null;
        }
        float targetX = ALL_MELODY_START_X;
        float targetY = ALL_MELODY_START_Y;
        //更新位置
        for(MelodySingle single:singles){
            single.setTarget(targetX,targetY,false);
            //update下一个
            targetX += single.melodyHb.width + MELODY_DISTANCE_X;
        }
        //确认下一个currentSingle
        if(singles.size()>0){
            setCurrentMelody(singles.get(0));
        }
    }

    public static void update(){
        if(lastSingle!=null){
            lastSingle.update();
        }
        for(MelodySingle single:singles){
            single.update();
        }
        updateFloatWordEffect();
    }

    public static void render(SpriteBatch sb){
        if(lastSingle!=null){
            lastSingle.render(sb);
        }
        for(MelodySingle single:singles){
            single.render(sb);
        }
    }

    public static void addMelody(MelodySingle single){
        float targetX = ALL_MELODY_START_X;
        float targetY = ALL_MELODY_START_Y - NOTE_DISTANCE_Y;
        for(MelodySingle s:singles){
            targetX += s.melodyHb.width + MELODY_DISTANCE_X;
        }

        //添加前若无melody，则设置为current
        if(singles.size()==0){
            setCurrentMelody(single);
        }
        singles.add(single);
        single.isAppearing = true;
        single.setTarget(targetX,targetY,true);
        single.setTarget(targetX,targetY+NOTE_DISTANCE_Y,false);
    }

    public static void triggerNote(AbstractCard card){
        if(currentSingle!=null){
            MelodyNote note = currentSingle.currentNote;
            if(note!=null){
                if(note.trigger(card)){
                    note.finished();
                    boolean move = currentSingle.moveToNextNote();
                    if(!move){
                        removeCurrentMelody();
                    }
                }
                else {
                    //移除旋律
                    removeCurrentMelody();
                }
            }
        }
    }

    private static float floatWordTimer = 0;

    private static void updateFloatWordEffect(){
        if(currentSingle!=null){
            floatWordTimer-= Gdx.graphics.getDeltaTime();
            if(floatWordTimer<=0F){
                floatWordTimer = MathUtils.random(0.25F,0.45F);
                AbstractDungeon.effectsQueue.add(new FloatWordEffect());
            }
        }
    }

    @SpirePatch(clz = AbstractPlayer.class,method = "useCard")
    public static class UseCardTriggerPatch{
        @SpireInsertPatch(rloc = 18)
        public static void Insert(AbstractPlayer _inst, AbstractCard c, AbstractMonster m, int energyOnUse){
            //主动打出
            if(!c.isInAutoplay&&!c.dontTriggerOnUseCard)
                triggerNote(c);
        }
    }

    //渲染和更新统一在手牌前
    @SpirePatch(clz = CardGroup.class,method = "update")
    public static class UpdateMelodyPatch{
        @SpirePrefixPatch
        public static void Prefix(CardGroup _inst){
            if(AbstractDungeon.player!=null&&_inst == AbstractDungeon.player.hand){
                update();
            }
        }
    }

    @SpirePatch(clz = MonsterGroup.class,method = "render")
    public static class RenderMelodyPatch{
        @SpirePostfixPatch
        public static void Postfix(MonsterGroup _inst, SpriteBatch sb){
            if(AbstractDungeon.getMonsters()==_inst){
                render(sb);
            }
        }
    }




    public static class MelodySingle{

        //这个实际表示激活过而非只是【目前的】
        public boolean isCurrent = false;
        public boolean finished = false;
        public boolean isAppearing = false;
        public boolean isFading = false;
        private float hbAlpha = 1F;
        private float mulAlpha = 1F;

        public float currentAimX = 0F;
        public float targetAimX;

        public float currentTotalX;
        public float targetTotalX;
        public float currentTotalY;
        public float targetTotalY;

        public String melodyName = "";

        public int currentIndex = 0;
        public MelodyNote finalNote;
        public MelodyNote currentNote;
        public MelodyNote tipNote;

        //持续期间是否触发心音
        public boolean alwaysHeart = false;

        private Color hbShadowColor = new Color(0.0F, 0.0F, 0.0F, 0F);
        private Color melodyColor = new Color(1F,0.84F,0F,0F);
        private Color outlineColor = new Color(0.6F, 0.93F, 0.98F, 0F);
        private Color textColor = new Color(1F,1F,1F,0F);

        public MelodySingle(int count){
            for(int i =0;i<count;i++){
                //notes.add(new MelodyNote(i,0,"EMM"));
            }
            this.melodyHb = new Hitbox((MELODY_START_X+count*NOTE_DISTANCE_X)*Settings.scale,BAR_HEIGHT);
            targetAimX = MELODY_START_X;
            this.moveToNextNote();
        }

        public MelodySingle(String name,ArrayList<MelodyNote> notes,MelodyNote finalNote){
            this.melodyName = name;
            this.notes.addAll(notes);
            this.finalNote = finalNote;
            this.melodyHb = new Hitbox(MELODY_START_X+this.notes.size()*NOTE_DISTANCE_X,60F*Settings.scale);
            targetAimX = MELODY_START_X;
            this.moveToNextNote();
        }

        public ArrayList<MelodyNote> notes = new ArrayList<>();

        public Hitbox melodyHb;

        public void setTarget(float x,float y,boolean changeCurrent){
            this.targetTotalX = x;
            this.targetTotalY = y;
            if(changeCurrent){
                currentTotalX = x;
                currentTotalY = y;
            }
        }

        //若移动成功，返回true，否则false执行移除
        public boolean moveToNextNote() {
            if (currentNote == null && notes.size() > 0) {
                currentNote = notes.get(0);
                currentIndex = 0;
                return true;
            } else if (currentNote != null && notes.contains(currentNote)) {
                int i = notes.indexOf(currentNote) + 1;
                if (notes.size() > i) {
                    currentNote = notes.get(i);
                    currentIndex = i;
                    return true;
                }
            }
            return false;
        }

        public void started(){
            isCurrent = true;
            if(alwaysHeart){
                HeartPatch.AlwaysHeart = true;
            }
            //power
            AnswerInWindPower p = (AnswerInWindPower) AbstractDungeon.player.getPower(AnswerInWindPower.POWER_ID);
            if(p!=null){
                p.triggerWhenMelodyStart(this);
            }
        }

        public void finished(){
            //当前为最后序号，且当前音符已完成
            finished = true;
            if(currentIndex==notes.size()-1&&currentNote!=null&&currentNote.finished){
                if(finalNote!=null){
                    finalNote.finished();
                }
                AbstractPower t = AbstractDungeon.player.getPower(TranceDreamPower.POWER_ID);
                if(t!=null){
                    t.onSpecificTrigger();
                }
            }

            if(alwaysHeart){
                HeartPatch.AlwaysHeart = false;
            }
        }

        public void update(){
            updateTotalPosition();
            updateBarAnimation();
            updateHbAlpha();
        }

        //这里的坐标为【左下角】的坐标
        private void updateTotalPosition(){
            this.currentTotalX = MathHelper.uiLerpSnap(currentTotalX,targetTotalX);
            this.currentTotalY = MathHelper.uiLerpSnap(currentTotalY,targetTotalY);
            this.melodyHb.translate(currentTotalX,currentTotalY);

            tipNote = null;
            for(MelodyNote note:notes){
                note.update(currentTotalX + MELODY_START_X,melodyHb.cY);
                if(note.noteHb.hovered){
                    tipNote = note;
                }
            }
            if(finalNote!=null) {
                finalNote.update(currentTotalX + melodyHb.width,melodyHb.cY);
                if(finalNote.noteHb.hovered){
                    tipNote = finalNote;
                }
            }

        }

        private void updateBarAnimation(){
            this.targetAimX = MELODY_START_X + currentIndex * NOTE_DISTANCE_X;
            this.currentAimX = MathHelper.uiLerpSnap(currentAimX,targetAimX);
        }

        private void updateHbAlpha() {
            if (melodyHb.x > Settings.WIDTH / 2F) {
                //从屏幕中右侧开始的旋律最大颜色衰减 1 ~ 0.4F
                mulAlpha = 1F - 0.6F * (2 * melodyHb.x - Settings.WIDTH) / Settings.WIDTH;
            } else {
                mulAlpha = 1F;
            }
            if (isAppearing) {
                this.hbAlpha = MathHelper.fadeLerpSnap(hbAlpha, 1F);
                if (hbAlpha == 1F) {
                    isAppearing = false;
                }
            } else if (isFading) {
                this.hbAlpha = MathHelper.fadeLerpSnap(hbAlpha, 0F);

                if (hbAlpha == 0F) {
                    isFading = false;
                }
            }
            this.hbShadowColor.a = hbAlpha * 0.5F * mulAlpha;
            this.melodyColor.a = hbAlpha * mulAlpha;
            this.outlineColor.a = hbAlpha * mulAlpha;
            this.textColor.a = hbAlpha * mulAlpha;
        }

        public void render(SpriteBatch sb){
            float x = melodyHb.cX - melodyHb.width/2F;
            float y = melodyHb.cY - melodyHb.height/2F;
            renderMelodyBg(sb,x,y);
            if(isCurrent){
                renderMelodyBar(sb,x,y);
                renderOutline(sb,x,y);
            }
            for(MelodyNote note:notes){
                note.render(sb,x+MELODY_START_X,y,(currentSingle==this&&currentIndex==note.index)?this.hbAlpha*mulAlpha:this.hbAlpha*mulAlpha*0.5F);
            }
            if(finalNote!=null) {
                finalNote.render(sb, x + melodyHb.width, y, (currentSingle == this) ? this.hbAlpha * mulAlpha : this.hbAlpha * mulAlpha * 0.5F);
            }

            //render Tip & Text
            renderText(sb,x,y);
            if(!finished&&tipNote!=null && AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT && !AbstractDungeon.isScreenUp) {
                TipHelper.renderGenericTip(tipNote.noteHb.x+tipNote.noteHb.width + 30F*Settings.scale,tipNote.noteHb.y+tipNote.noteHb.height, melodyName,tipNote.getDescription());
            }
        }

        private void renderMelodyBg(SpriteBatch sb,float x,float y){
            sb.setColor(this.hbShadowColor);
            sb.draw(ImageMaster.HB_SHADOW_L, x - BAR_HEIGHT, y - MELODY_BG_OFFSET_X + 3.0F * Settings.scale, BAR_HEIGHT, BAR_HEIGHT);
            sb.draw(ImageMaster.HB_SHADOW_B, x, y - MELODY_BG_OFFSET_X + 3.0F * Settings.scale, melodyHb.width, BAR_HEIGHT);
            sb.draw(ImageMaster.HB_SHADOW_R, x + melodyHb.width, y - MELODY_BG_OFFSET_X + 3.0F * Settings.scale, BAR_HEIGHT, BAR_HEIGHT);
        }

        private void renderMelodyBar(SpriteBatch sb,float x,float y){
            sb.setColor(melodyColor);
            sb.draw(ImageMaster.HEALTH_BAR_L, x - BAR_HEIGHT, y + MELODY_BAR_OFFSET_Y, BAR_HEIGHT, BAR_HEIGHT);
            sb.draw(ImageMaster.HEALTH_BAR_B, x, y + MELODY_BAR_OFFSET_Y, currentAimX, BAR_HEIGHT);
            sb.draw(ImageMaster.HEALTH_BAR_R, x + currentAimX, y + MELODY_BAR_OFFSET_Y, BAR_HEIGHT, BAR_HEIGHT);
        }

        private void renderOutline(SpriteBatch sb, float x, float y){
            sb.setColor(outlineColor);
            sb.setBlendFunction(770, 1);
            sb.draw(ImageMaster.BLOCK_BAR_L, x - BAR_HEIGHT, y + MELODY_BAR_OFFSET_Y, BAR_HEIGHT, BAR_HEIGHT);
            sb.draw(ImageMaster.BLOCK_BAR_B, x, y + MELODY_BAR_OFFSET_Y, melodyHb.width, BAR_HEIGHT);
            sb.draw(ImageMaster.BLOCK_BAR_R, x + melodyHb.width, y + MELODY_BAR_OFFSET_Y, BAR_HEIGHT, BAR_HEIGHT);
            sb.setBlendFunction(770, 771);
        }

        private void renderText(SpriteBatch sb,float x,float y){
            float tmp = this.textColor.a;
            FontHelper.renderFontCentered(sb, FontHelper.healthInfoFont, melodyName,x + MELODY_START_X/2F, y + MELODY_BAR_OFFSET_Y + melodyHb.height - 5.0F * Settings.scale, textColor);
            this.textColor.a = tmp;
        }

    }

    public static class MelodyNote{

        public MelodyNote(MelodySubscriber source,int index,int noteType,String description){
            this.source = source;
            this.specialAmount = source.initializeSpecialAmount(index==-1);
            this.index = index;
            this.setNote(noteType);
            this.description = description;
            noteHb = new Hitbox(80F* Settings.scale,100F*Settings.scale);
        }

        public Color renderColor = Color.WHITE.cpy();
        public int index;
        public boolean finished = false;

        //用来区别同一旋律名的不同阶段旋律数值
        public int specialAmount;
        //调用来源
        public MelodySubscriber source;

        //用来实现定位，悬浮提示功能
        public Hitbox noteHb;

        //0-任意 1-攻击牌 2-技能牌 3-其他牌
        public int noteType;
        public Texture image;
        public Texture countCircle = ImageMaster.DECK_COUNT_CIRCLE;
        public String description = "";

        //完成音符的调用内容
        public ArrayList<AbstractGameAction> actions = new ArrayList<>();

        public String getDescription() {
            if (noteType >= 0 && noteType <= 4)
                return melodyStrings.TEXT[noteType] + this.description;
            else
                return this.description;
        }

        //若符合，返回true
        public boolean trigger(AbstractCard c){
            AbstractCard.CardType cardType = c.type;
            //特化
//            if(c.cardID.equals(UnknownCloud_Eyjafjalla.ID)){
//                cardType = ((UnknownCloud_Eyjafjalla)c).changeType();
//            }
            if(c instanceof AbstractEyjafjallaCard){
                if(((AbstractEyjafjallaCard) c).ignoreMelodyType())
                    return true;
            }
            switch (this.noteType){
                case 0:
                    return true;
                case 1:
                    return cardType== AbstractCard.CardType.ATTACK;
                case 2:
                    return cardType== AbstractCard.CardType.SKILL;
                case 3:
                    return cardType!= AbstractCard.CardType.ATTACK&&cardType!= AbstractCard.CardType.SKILL;
            }
            return false;
        }

        public void finished() {
            this.finished = true;
            //flash
            AbstractDungeon.topLevelEffects.add(new MelodyNoteFlashEffect(this));
            for (AbstractGameAction action : source.getNoteActions(index==-1,this.specialAmount)) {
                AbstractDungeon.actionManager.addToBottom(action);
            }
            if (index == 0) {
                AbstractRelic mother = AbstractDungeon.player.getRelic(UnknownMotherGoose.ID);
                if (mother != null) {
                    mother.onTrigger();
                    for (AbstractGameAction action : source.getNoteActions(index==-1,this.specialAmount)) {
                        AbstractDungeon.actionManager.addToBottom(action);
                    }
                }
            }
            AbstractRelic witch = AbstractDungeon.player.getRelic(WitchAddax.ID);
            if (witch != null) {
                witch.onTrigger();
            }
            if(noteType==2||noteType==0){
                AbstractRelic god = AbstractDungeon.player.getRelic(GodRoll.ID);
                if(god!=null){
                    god.onTrigger();
                }
            }
        }

        //传入melody第一个音符所在的位置
        public void update(float melodyX,float melodyY){
            noteHb.move(melodyX + (index>=0?(index*NOTE_DISTANCE_X):0F),melodyY-20F*Settings.scale - noteHb.height/2F);
            noteHb.update();
        }

        public void render(SpriteBatch sb,float x,float y,float alpha){
            //完成整段的finalNote为-1
            float aX = x + MELODY_BG_OFFSET_X + (index>=0?(index*NOTE_DISTANCE_X):0F);
            float aY = y;
            this.renderColor.a = alpha;
            sb.setColor(renderColor);
            sb.draw(countCircle, aX-32F*Settings.scale, aY+MELODY_BAR_OFFSET_Y, 64.0F, 64.0F, 64F, 64F, Settings.scale, Settings.scale, 0.0F, 0, 0, 128, 128, false, false);
            sb.draw(image,aX-32F*Settings.scale, aY+MELODY_BAR_OFFSET_Y-NOTE_DISTANCE_Y/2F, 64.0F, 64.0F, 64F, 64F, Settings.scale, Settings.scale, 0.0F, 0, 0, 64, 64, false, false);
        }

        public void setNote(int noteType){
            this.noteType = noteType;
            switch (this.noteType){
                case 0:
                {
                    this.image = ImageMaster.INTENT_DEBUFF2;
                    break;
                }
                case 1:
                {
                    this.image = ImageMaster.INTENT_ATK_TIP_3;
                    break;
                }
                case 2:
                {
                    this.image = ImageMaster.INTENT_DEFEND_BUFF;
                    break;
                }
                case 3:
                {
                    this.image = ImageMaster.INTENT_MAGIC;
                    break;
                }
                default:
                    image = ImageMaster.INTENT_UNKNOWN;
            }
        }
    }

    static {
        melodyStrings = CardCrawlGame.languagePack.getUIString(StringHelper.MELODY);

        ALL_MELODY_START_X = Settings.WIDTH/2F - 500F*Settings.scale;
        ALL_MELODY_START_Y = Settings.HEIGHT/2F + 140F*Settings.scale;

        MELODY_START_X = 50F*Settings.scale;
        NOTE_DISTANCE_X = 100F*Settings.scale;
        NOTE_DISTANCE_Y = 80F*Settings.scale;
        BAR_HEIGHT = 35F*Settings.scale;
        MELODY_DISTANCE_X = 50F*Settings.scale;

        MELODY_BG_OFFSET_X = 31F*Settings.scale;
        MELODY_BAR_OFFSET_Y = -28F*Settings.scale;
    }
}
